﻿using Bit.Art.Core.Models;
using Bit.Art.Engine;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Text;

namespace bit.art.test
{
#if UNITTEST
    [TestClass]
    public class 撮合引擎异常测试
    {
        [TestMethod]
        public void 以单一价格给撮合引擎下达超出容量的订单()
        {
            var orderCapacity = 1000;
            var market = "BTC/USDT";
            var orderbook = new MemoryOrderBookRepo(market, orderCapacity: orderCapacity);
            decimal bidprice = 1000, askprice = 1001;
            ulong orderid;
            Order[] matched;

            for (var i = 0; i < orderCapacity / 2; ++i)
            {
                orderbook.Push(new Order(Guid.NewGuid(), 2, (uint)TradeSide.Buy, market, bidprice, 1, 1, (uint)OrderType.Limit, 1000, DateTime.Now),
                    out orderid, out matched);

                orderbook.Push(new Order(Guid.NewGuid(), 1, (uint)TradeSide.Sell, market, askprice, 1, 1, (uint)OrderType.Limit, 1000, DateTime.Now),
                    out orderid, out matched);
            }

            Assert.AreEqual(orderCapacity, orderbook.Capacity);
            Assert.AreEqual(orderCapacity, orderbook.Count);

            // 再添加一笔新的订单
            var response = orderbook.Push(new Order(Guid.NewGuid(), 2, (uint)TradeSide.Buy, market, bidprice, 1, 1, (uint)OrderType.Limit, 1000, DateTime.Now),
                out orderid, out matched);

            Assert.AreEqual(OrderFillType.InsertLater, response);
            Assert.AreEqual(orderCapacity, orderbook.Capacity);
            Assert.AreEqual(orderCapacity, orderbook.Count);

            // 成交一单，应该可以再次插入新订单
            response = orderbook.Push(new Order(Guid.NewGuid(), 2, (uint)TradeSide.Sell, market, bidprice, 1, 1, (uint)OrderType.Limit, 1000, DateTime.Now),
                    out orderid, out matched);
            Assert.AreEqual(OrderFillType.Filled, response);
            Assert.AreEqual(orderCapacity, orderbook.Capacity);
            Assert.AreEqual(orderCapacity - 1, orderbook.Count);

            response = orderbook.Push(new Order(Guid.NewGuid(), 2, (uint)TradeSide.Buy, market, bidprice, 1, 1, (uint)OrderType.Limit, 1000, DateTime.Now),
                out orderid, out matched);

            Assert.AreEqual(OrderFillType.NotFilled, response);
            Assert.AreEqual(orderCapacity, orderbook.Capacity);
            Assert.AreEqual(orderCapacity, orderbook.Count);

            // 再成交一单，应该可以再次插入新订单
            response = orderbook.Push(new Order(Guid.NewGuid(), 2, (uint)TradeSide.Sell, market, bidprice, 1, 1, (uint)OrderType.Limit, 1000, DateTime.Now),
                    out orderid, out matched);
            Assert.AreEqual(OrderFillType.Filled, response);
            Assert.AreEqual(orderCapacity, orderbook.Capacity);
            Assert.AreEqual(orderCapacity - 1, orderbook.Count);
        }

        [TestMethod]
        public void 以多种价格给撮合引擎下达超出容量的订单()
        {
            var orderCapacity = 1000;
            var market = "BTC/USDT";
            var orderbook = new MemoryOrderBookRepo(market, orderCapacity: orderCapacity);
            decimal bidprice = 1000, askprice = 1001;
            ulong orderid;
            Order[] matched;

            for (var i = 0; i < orderCapacity / 2; ++i)
            {
                var currentBid = bidprice - (i / 100);
                orderbook.Push(new Order(Guid.NewGuid(), 2, (uint)TradeSide.Buy, market, currentBid, 1, 1, (uint)OrderType.Limit, 1000, DateTime.Now),
                    out orderid, out matched);

                var currentAsk = askprice + (i / 100);
                orderbook.Push(new Order(Guid.NewGuid(), 1, (uint)TradeSide.Sell, market, currentAsk, 1, 1, (uint)OrderType.Limit, 1000, DateTime.Now),
                    out orderid, out matched);
            }

            Assert.AreEqual(orderCapacity, orderbook.Capacity);
            Assert.AreEqual(orderCapacity, orderbook.Count);

            // 再添加一笔新的订单
            var response = orderbook.Push(new Order(Guid.NewGuid(), 2, (uint)TradeSide.Buy, market, bidprice, 1, 1, (uint)OrderType.Limit, 1000, DateTime.Now),
                out orderid, out matched);

            Assert.AreEqual(OrderFillType.InsertLater, response);
            Assert.AreEqual(orderCapacity, orderbook.Capacity);
            Assert.AreEqual(orderCapacity, orderbook.Count);

            // 成交一单，应该可以再次插入新订单
            response = orderbook.Push(new Order(Guid.NewGuid(), 2, (uint)TradeSide.Sell, market, bidprice, 1, 1, (uint)OrderType.Limit, 1000, DateTime.Now),
                    out orderid, out matched);
            Assert.AreEqual(OrderFillType.Filled, response);
            Assert.AreEqual(orderCapacity, orderbook.Capacity);
            Assert.AreEqual(orderCapacity - 1, orderbook.Count);
        }

        [TestMethod]
        public void 大量卖单撮合()
        {
            var orderCapacity = 1000;
            var market = "BTC/USDT";
            var orderbook = new MemoryOrderBookRepo(market, orderCapacity: orderCapacity);
            decimal bidprice = 1000;
            ulong orderid;
            Order[] matched;

            for (var i = 0; i < orderCapacity; ++i)
            {
                var currentBid = bidprice - (i / 100);
                orderbook.Push(new Order(Guid.NewGuid(), 2, (uint)TradeSide.Buy, market, currentBid, 1, 1, (uint)OrderType.Limit, 1000, DateTime.Now),
                    out orderid, out matched);
            }

            // 再添加一笔新的大订单
            var response = orderbook.Push(new Order(Guid.NewGuid(), 2, (uint)TradeSide.Sell, market, 0.0001m, orderCapacity, orderCapacity, (uint)OrderType.Limit, 1000, DateTime.Now),
                out orderid, out matched);
            Assert.AreEqual(OrderFillType.Filled, response);
            Assert.AreEqual(orderCapacity, orderbook.Capacity);
            Assert.AreEqual(0, orderbook.Count);

            for (var i = 0; i < orderCapacity; ++i)
            {
                var currentBid = bidprice - (i / 100);
                response = orderbook.Push(new Order(Guid.NewGuid(), 2, (uint)TradeSide.Buy, market, currentBid, 1, 1, (uint)OrderType.Limit, 1000, DateTime.Now),
                    out orderid, out matched);
                Assert.AreEqual(OrderFillType.NotFilled, response);
            }

            // 再下一个大订单，但是部分成交
            response = orderbook.Push(new Order(Guid.NewGuid(), 2, (uint)TradeSide.Sell, market, 0.0001m, orderCapacity + 1, orderCapacity + 1, (uint)OrderType.Limit, 1000, DateTime.Now),
                out orderid, out matched);
            Assert.AreEqual(OrderFillType.PartialFilled, response);
            Assert.AreEqual(orderCapacity, orderbook.Capacity);
            Assert.AreEqual(1, orderbook.Count);
            
            response = orderbook.Push(new Order(Guid.NewGuid(), 2, (uint)TradeSide.Buy, market, 1, 1, 1, (uint)OrderType.Limit, 1000, DateTime.Now),
                out orderid, out matched);
            Assert.AreEqual(OrderFillType.Filled, response);
            Assert.AreEqual(orderCapacity, orderbook.Capacity);
            Assert.AreEqual(0, orderbook.Count);
        }
    }
#endif
}
